package com.thread.exe;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class DifferentInterrupt {
	private static final ScheduledThreadPoolExecutor cancelExec = new ScheduledThreadPoolExecutor(4);

	//不好的地方在于不知道调用线程的中断策略情况下贸然中断， 比如该线程在处理完改方法后还要执行别的内容， 如果此时run 提前结束了，那么会导致该线程莫名被中断。
	public static void timedRun1(Runnable r, long timeout, TimeUnit unit) {
		final Thread taskThread = Thread.currentThread();
		cancelExec.schedule(new Runnable() {

			@Override
			public void run() {
				taskThread.interrupt();
			}
		}, timeout, unit);
		r.run();
	}

	//开辟了2个线程来分别执行任务和 中断任务， 不好的地方是采用了join的机制， 导致了不知道是因为任务正常退出而返回， 还是 因为join超时而返回。
	public static void timedRun2(Runnable r, long timeout, TimeUnit unit) throws InterruptedException {
		class RethrowableTask implements Runnable {
			private volatile Throwable t;

			@Override
			public void run() {
				try {
					r.run();
				} catch (Exception e) {
					t = e;
				}
			}

			void rethrow() {
				if (t != null) {
					throw launderThrowable(t);
				}
			}

			public RuntimeException launderThrowable(Throwable t) {
				if (t instanceof RuntimeException)
					return (RuntimeException) t;
				else if (t instanceof Error)
					throw (Error) t;
				else
					throw new IllegalStateException("Not unchected", t);
			}

		}

		RethrowableTask task = new RethrowableTask();
		final Thread taskThread = new Thread(task);
		taskThread.start();
		cancelExec.schedule(new Runnable() {

			@Override
			public void run() {
				taskThread.interrupt();
			}
		}, timeout, unit);
		taskThread.join(unit.toMillis(timeout));
		task.rethrow();
	}

	//借助于Future 来完成定时阻塞和取消任务， cancel(true) 跟踪代码可以看到内部调用了interrupted。
	public static void timedRun3(Runnable r, long timeout, TimeUnit unit) throws InterruptedException {
		Future<?> task = cancelExec.submit(r);
		try {
			task.get(timeout, unit);
		} catch (ExecutionException e) {
			throw launderThrowable(e);
		} catch (TimeoutException e) {
			task.cancel(true);
		}
	}

	public static RuntimeException launderThrowable(Throwable t) {
		if (t instanceof RuntimeException)
			return (RuntimeException) t;
		else if (t instanceof Error)
			throw (Error) t;
		else
			throw new IllegalStateException("Not unchected", t);
	}
}
